package skiree.host.abetsy.api.service.impl;

import cn.hutool.core.net.URLDecoder;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.springframework.stereotype.Component;
import skiree.host.abetsy.api.dao.AnimeDao;
import skiree.host.abetsy.api.dao.CommentDao;
import skiree.host.abetsy.api.dao.ConfigDao;
import skiree.host.abetsy.api.dao.EpisodeDao;
import skiree.host.abetsy.api.service.AnimeService;
import skiree.host.abetsy.api.service.global.GlobalDIYService;
import skiree.host.abetsy.api.vessel.Result;
import skiree.host.abetsy.model.LocalAnime;
import skiree.host.abetsy.model.LocalComment;
import skiree.host.abetsy.model.LocalConfig;
import skiree.host.abetsy.model.LocalEpisode;
import skiree.host.abetsy.service.util.DouBanUtil;
import skiree.host.abetsy.service.util.PlatFormUtil;

import javax.annotation.Resource;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Component
public class AnimeServiceImpl implements AnimeService {

    @Resource
    private GlobalDIYService globalDIYService;

    @Resource
    private AnimeDao animeDao;

    @Resource
    private EpisodeDao episodeDao;

    @Resource
    private CommentDao commentDao;

    @Resource
    private ConfigDao configDao;

    private final Object lockIncrement = new Object();

    private final Object lockComplete = new Object();

    @Override
    public Result list(String query, int pageNum, int pageSize) {
        Page<Map<String, Object>> page = new Page<>(pageNum, pageSize);
        MPJLambdaWrapper<LocalAnime> wrapper = JoinWrappers.lambda(LocalAnime.class).selectAll(LocalAnime.class).selectCount(LocalEpisode::getId, "sub").leftJoin(LocalEpisode.class, LocalEpisode::getAnimeId, LocalAnime::getId).like(LocalAnime::getTitle, query).groupBy(LocalAnime::getId).orderByDesc(LocalAnime::getTime);
        IPage<Map<String, Object>> animePage = animeDao.selectJoinMapsPage(page, wrapper);
        Map<String, Object> data = new HashMap<>();
        data.put("total", animePage.getTotal());
        data.put("pageNum", pageNum);
        data.put("pageSize", pageSize);
        data.put("anime", animePage.getRecords());
        return Result.success(data);
    }

    @Override
    public Result add(LocalAnime localAnime) {
        QueryWrapper<LocalAnime> animeQuery = new QueryWrapper<>();
        animeQuery.eq("title", localAnime.getTitle());
        animeQuery.eq("season", localAnime.getSeason());
        LocalAnime animeDb = animeDao.selectOne(animeQuery);
        if (animeDb != null) {
            return Result.error(501, "此影视已存在!");
        }
        if (localAnime.getUrl() == null) {
            try {
                DouBanUtil.douBanLink(localAnime);
                if (localAnime.getUrl() == null || localAnime.getDouBan() == null)
                    return Result.error(501, "获取豆瓣源失败,请手动指定源!");
                localAnime.setTime(new Date());
                animeDao.insert(localAnime);
                return Result.success(localAnime);
            } catch (Exception ignore) {
                return Result.error(501, "获取豆瓣源失败,请手动指定源!");
            }
        } else {
            if (localAnime.getUrl().startsWith("https://movie.douban.com/subject/")) {
                try {
                    Matcher mDouBanId = Pattern.compile("https://movie.douban.com/subject/(\\d+)/").matcher(localAnime.getUrl());
                    if (mDouBanId.find()) {
                        localAnime.setDouBan(Integer.parseInt(mDouBanId.group(1)));
                        localAnime.setTime(new Date());
                        if (StrUtil.isBlank(localAnime.getImg())){
                            DouBanUtil.supplementAnimeCover(localAnime, localAnime.getUrl());
                        }
                        if (StrUtil.isBlank(localAnime.getImg())){
                            localAnime.setImg("https://img2.doubanio.com/cuphead/movie-static/pics/movie_default_large.png");
                        }
                        animeDao.insert(localAnime);
                        return Result.success(localAnime);
                    }
                } catch (Exception e) {
                    return Result.error(501, "豆瓣链接格式异常!");
                }
            }
        }
        return Result.error(501, "豆瓣链接格式异常!");
    }

    @Override
    public Result edit(LocalAnime localAnime) {
        QueryWrapper<LocalAnime> animeQuery = new QueryWrapper<>();
        animeQuery.eq("title", localAnime.getTitle());
        animeQuery.eq("season", localAnime.getSeason());
        animeQuery.ne("id", localAnime.getId());
        LocalAnime animeCk = animeDao.selectOne(animeQuery);
        if (animeCk != null) {
            return Result.error(501, "此影视名称已存在!");
        }
        LocalAnime animeDb = animeDao.selectById(localAnime.getId());
        animeDb.setTitle(localAnime.getTitle());
        animeDb.setSeason(localAnime.getSeason());
        animeDao.updateById(animeDb);
        return Result.success(animeDb);
    }

    @Override
    public void delete(int id) {
        animeDao.deleteById(id);
        QueryWrapper<LocalEpisode> episodeQuery = new QueryWrapper<>();
        episodeQuery.eq("anime_id", id);
        List<LocalEpisode> localEpisodes = episodeDao.selectList(episodeQuery);
        for (LocalEpisode episode : localEpisodes) {
            QueryWrapper<LocalComment> commentQuery = new QueryWrapper<>();
            commentQuery.eq("episode_id", episode.getId());
            commentDao.delete(commentQuery);
        }
        episodeDao.delete(episodeQuery);
    }

    @Override
    public void increment(int id) {
        synchronized (lockIncrement) {
            supplementEpisode(id);
            // 增量处理
            QueryWrapper<LocalEpisode> episodeQuery = new QueryWrapper<>();
            episodeQuery.eq("anime_id", id);
            episodeQuery.and(qr -> qr.in("status", "init", "error"));
            List<LocalEpisode> localEpisodes = episodeDao.selectList(episodeQuery);
            for (LocalEpisode episode : localEpisodes) {
                loadBarrage(episode);
            }
        }
    }

    @Override
    public void complete(int id) {
        synchronized (lockComplete) {
            supplementEpisode(id);
            // 全量处理
            QueryWrapper<LocalEpisode> episodeQuery = new QueryWrapper<>();
            episodeQuery.eq("anime_id", id);
            List<LocalEpisode> localEpisodes = episodeDao.selectList(episodeQuery);
            for (LocalEpisode episode : localEpisodes) {
                loadBarrage(episode);
            }
        }
    }

    public void loadBarrage(LocalEpisode episode) {
        globalDIYService.loadDanMu(episode);
    }

    public void supplementEpisode(int id) {
        QueryWrapper<LocalConfig> configQuery = new QueryWrapper<>();
        configQuery.eq("name", "priority");
        LocalConfig localConfig = configDao.selectOne(configQuery);
        // 开始正式的处理
        LocalAnime localAnime = animeDao.selectById(id);
        if (localAnime == null) return;
        try {
            Map<Integer, LocalEpisode> episodeMap = new HashMap<>();
            String result = HttpUtil.get(localAnime.getUrl(), CharsetUtil.CHARSET_UTF_8);
            if (StrUtil.isEmpty(localAnime.getImg())) supplementAnimeCover(localAnime, result);
            Matcher matcher = Pattern.compile("\\{play_link(.*?)}").matcher(result);
            while (matcher.find()) {
                JSONObject link = JSONUtil.parseObj(matcher.group());
                Integer ep = Integer.parseInt(link.getStr("ep"));
                String playLink = link.getStr("play_link");
                playLink = URLDecoder.decode(playLink, CharsetUtil.CHARSET_UTF_8);
                playLink = playLink.replace("https://www.douban.com/link2/?url=", "");
                playLink = playLink.split(".html")[0] + ".html";
                playLink = playLink.replace("http:", "https:");
                if (playLink.contains("?bsource=doubanh5")) {
                    playLink = playLink.split("\\?bsource=doubanh5")[0];
                }
                LocalEpisode episode = new LocalEpisode();
                episode.setAnimeId(localAnime.getId());
                episode.setTitle("第" + ep + "集");
                episode.setEpisodeIndex(ep);
                episode.setUrl(playLink);
                episode.setStatus("init");
                episode.setTime(new Date());
                // 判断是否已经存在了
                if (episodeMap.containsKey(ep) && localConfig != null) {
                    List<Map> priorityInfo = JSONUtil.toList(localConfig.getValue(),Map.class);
                    // 根据全局设置的优先级处理
                    int oldMark = Integer.parseInt(priorityInfo.stream().filter(x->x.get("mark").equals(PlatFormUtil.parse(episodeMap.get(ep).getUrl()))).findFirst().get().get("index").toString());
                    int newMark = Integer.parseInt(priorityInfo.stream().filter(x->x.get("mark").equals(PlatFormUtil.parse(episode.getUrl()))).findFirst().get().get("index").toString());
                    if (newMark < oldMark){
                        episodeMap.put(episode.getEpisodeIndex(), episode);
                    }
                } else {
                    episodeMap.put(episode.getEpisodeIndex(), episode);
                }
            }
            // 和数据库中已经存在的数据比对
            QueryWrapper<LocalEpisode> episodeQuery = new QueryWrapper<>();
            episodeQuery.eq("anime_id", id);
            Map<Integer, LocalEpisode> indexEpisodesMap = episodeDao.selectList(episodeQuery).stream().collect(Collectors.toMap(LocalEpisode::getEpisodeIndex, e -> e));
            for (LocalEpisode episode : episodeMap.values()) {
                if (indexEpisodesMap.get(episode.getEpisodeIndex()) == null) {
                    episodeDao.insert(episode);
                } else {
                    LocalEpisode episodeDb = indexEpisodesMap.get(episode.getEpisodeIndex());
                    if (!episodeDb.getUrl().equals(episode.getUrl())) {
                        // 重新设置状态
                        episodeDb.setStatus("init");
                        episodeDb.setUrl(episode.getUrl());
                        episodeDb.setTime(new Date());
                        episodeDao.updateById(episodeDb);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void supplementAnimeCover(LocalAnime localAnime, String result) {
        try {
            Matcher matcher = Pattern.compile("\"image\": \"(.*?)\"").matcher(result);
            if (matcher.find()) {
                localAnime.setImg(matcher.group(1));
                animeDao.updateById(localAnime);
            }
        } catch (Exception ignore) {
        }
    }

}
